package core;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.TableItem;

import ui.Logs;
import ui.MainWindow;
import db.DB_Abstract;

/**
 * Class for managing  game users, groups and more.
 * Static members and methods only.
 */
public class UserMgmt {
	
	// Static Members
	public static User currUser = null; // currently logged-in user
	public static List<Group> groupList;
	public static List<Continent> continentsList;
	public static List<Country> countriesList;
	public static List<Group> currUserGroups;
	public static List<QuestionLog> userQuestions;

	// No Constructor - All Static Methods
	
	/**
	 * invoked by the event handler of the UI "Login" button
	 * checks name and password given to set as the current user
	 * @return boolean whether the login was successful
	 */
	public static boolean login() {
		String name = getLoginNameFromUI();
		String password = getLoginPassFromUI();
		DB_Abstract myDB = MainWindow.myDB;
		 
		// empty values check
		if (name.equals("") || password.equals("")) {
			Logs.append("Enter some values please.");
			return false;
		}
		
		User user = myDB.getUser(name);
		if (user.getID() != -1) { 
			//user exist
			if (user.getPassword().equals(password)) {
				currUser = user;
				showUserInTitle();
				Logs.append(Logs.LOG_USER_LOGIN + " [" + name + "]");
				return true;
			}
		} // else
		Logs.append(Logs.LOG_USER_LOGIN_FAIL);
		return false; // user doesn't exist or password incorrect
	}
	
	
	/**
	 * invoked by the event handler of the UI "Create User" button
	 * creates new user inserts to DB and sets as the current user
	 * @return boolean whether the creation was successful
	 */
	public static boolean createNew() {
		String name = getCreateNameFromUI();
		String password = getCreatePassFromUI();
		DB_Abstract myDB = MainWindow.myDB;

		// empty values check
		if (name.equals("") || password.equals("")) {
			Logs.append("Enter some values please.");
			return false;
		}
		
		// check if user exists already
		if(myDB.getUser(name).getID() != -1){ //getUserFromDB(name) != null) {
			// user exists
			Logs.append(Logs.LOG_USER_CREATE_FAIL);
			return false; // user already exists
		}
		
		User user = new User(name, password);
		myDB.addNewUser(user);
		currUser = myDB.getUser(name);
		showUserInTitle();
		Logs.append(Logs.LOG_USER_CREATED + " [" + name + "]");
		return true;
	}
	
	
	/**
	 * sets currUser to NULL
	 * @return
	 */
	public static void logout() {
		currUser = null;
		showUserInTitle();
		MainWindow.tblStatistics.removeAll();
		MainWindow.lblStatisticsUser.setText("");
		Logs.append(Logs.LOG_USER_LOGOUT);
	}
	
	
	/**
	 * create new group, return if succeeded
	 */
	public static boolean createNewGroup() {
		String newGroupName = getNewGroupNameFromUI();
		int newGroupType = getNewGroupTypeFromUI();
		int newGroupQuestions = getNewGroupQuestionsFromUI();
		int newGroupContinentID = -1;
		int newGroupCountryID = -1;

		// sanity checks
		if (newGroupQuestions < 1 || newGroupName.equals("")) { 
			return false;
		} // else
		
		// handle type		
		switch (newGroupType) {
			
			case 1: //'cities by country'
				String newGroupCountryName = getNewGroupCountryFromUI();
				// sanity check
				if (!newGroupCountryName.equals("")) {
					int countryIndex;
					if((countryIndex = MainWindow.cmbNewGroupCountry.getSelectionIndex()) != -1) { // user selected a group
						newGroupCountryID = countriesList.get(countryIndex).getCountryId();
					};
				} else {
					return false;
				}
				break;
				
			case 2: //'cities by continent'
				String newGroupContinentName = getNewGroupContinentFromUI();
				// sanity check
				if (!newGroupContinentName.equals("")) {
					int continentIndex;
					if((continentIndex = MainWindow.cmbNewGroupContinent.getSelectionIndex()) != -1) { // user selected a group
						newGroupContinentID = continentsList.get(continentIndex).getContinentId();
					};
				} else {
					return false;
				}
				break;
				
			case 3: // 'all cities'
				// do nothing
				break;
				
			default:
				//can't happen
		}
		
		//create group
		Group newGroup = new Group(newGroupName, newGroupQuestions, newGroupCountryID, newGroupContinentID);
		Logs.append("Group " + newGroupName + " Created.");
		// add group to DB
		MainWindow.myDB.addNewGroup(newGroup);
		
		return true;
	}
	
	
	/**
	 * calcQuestionScore
	 */
	public static int calcQuestionScore(double lat, double lng, int seconds) {
		double score;
		double dist = distance(lat, lng, currUser.getCurrQuestion().getLatitude(), currUser.getCurrQuestion().getLongtitude());
		
		//calculate score
		score = 10000.0 / Math.max(dist, 1);
		score = Math.ceil(score); //round-up score
		
		Logs.append("Distance Penalty: " + (int)dist + " kilometers");
		
		return (int)score;
	}
	
	/**
	 * calculates distance between two sets of coordinates
	 */
	private static double distance(double lat1, double lon1, double lat2, double lon2) {
		double theta = lon1 - lon2;
		double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
		  
		dist = Math.acos(dist);
		dist = rad2deg(dist);
		dist = dist * 60 * 1.1515;
		dist = dist * 1.609344;
		
		return (dist);
	}
	
    /**
     * convert decimal degrees to radians for distance calculations
     */
    private static double deg2rad(double deg) {
    	return (deg * Math.PI / 180.0);
    }
    
    
    /**
     * convert radians to decimal degrees for distance calculations
     */
    private static double rad2deg(double rad) {
    	return (rad * 180.0 / Math.PI);
    }
	
	
	// UI Methods
	//***********
	
	/**
	 * getLoginNameFromUI
	 * @return
	 */
	private static String getLoginNameFromUI() {
		return MainWindow.txtLoginUserName.getText();
	}

	/**
	 * getLoginPassFromUI
	 * @return
	 */
	private static String getLoginPassFromUI() {
		return MainWindow.txtLoginUserPass.getText();
	}
	
	/**
	 * getCreateNameFromUI
	 * @return
	 */
	private static String getCreateNameFromUI() {
		return MainWindow.txtNewUserName.getText();
	}
	
	/**
	 * getCreatePassFromUI
	 * @return
	 */
	private static String getCreatePassFromUI() {
		return MainWindow.txtNewUserPass.getText();
	}

	/**
	 * adds the current user name to the application window title
	 * handles null user for logout
	 */
	private static void showUserInTitle() {
		if (currUser != null) {
			MainWindow.display.getShells()[0].setText(MainWindow.TITLE + " - " + currUser.getName());
		} else {
			MainWindow.display.getShells()[0].setText(MainWindow.TITLE);
		}
	}
	
	/**
	 * getNewGroupCountryFromUI
	 */
	private static String getNewGroupCountryFromUI() {
		return MainWindow.cmbNewGroupCountry.getText();
	}

	/**
	 * getNewGroupContinentFromUI
	 */
	private static String getNewGroupContinentFromUI() {
		return MainWindow.cmbNewGroupContinent.getText();
	}

	/**
	 * getNewGroupNameFromUI
	 */
	private static String getNewGroupNameFromUI() {
		return MainWindow.txtNewGroupName.getText();
	}
	
	/**
	 * getNewGroupQuestionsFromUI
	 */
	private static int getNewGroupQuestionsFromUI() {
		try{
			return Integer.parseInt(MainWindow.txtNewGroupQuestions.getText());
		} catch (NumberFormatException e) {
			return -1; // not a number
		}
	}

	/**
	 * getNewGroupTypeFromUI
	 */
	private static Integer getNewGroupTypeFromUI() {
		int newGroupType = 3;
		
		if (MainWindow.rbtn1ByCountry.getSelection()) {
			newGroupType = 1;
		}
		if (MainWindow.rbtn2ByContinent.getSelection()) {
			newGroupType = 2;
		}
		
		return newGroupType;
	}
	
	/**
	 * user wants to join a group, need to show him available groups in combobox
	 */	
	public static void populateGroupComboBox() {
		groupList = MainWindow.myDB.getGroups();
		//clear all to avoid mistakes and duplicates
		MainWindow.cmbJoinGroup.removeAll();
		// add all groups to combo
		for(Group grp : groupList) {
			MainWindow.cmbJoinGroup.add(grp.getName());
		}
	}
	
	/**
	 * user wants to create group, need to show him available countries in combobox
	 */	
	public static void populateCountryComboBox() {
		//do only if not populated already
		if (MainWindow.cmbNewGroupCountry.getItemCount() == 0 || MainWindow.cmbAddCityCountry.getItemCount() == 0) {
			// get all countries from DB
			countriesList = MainWindow.myDB.getCountriesSorted();
	
			// add all groups to combo-boxes in play and edit tabs
			for(Country cntry : countriesList) {
				MainWindow.cmbNewGroupCountry.add(cntry.getCountryName());
				MainWindow.cmbAddCityCountry.add(cntry.getCountryName());
			}
		}
	}
	
	/**
	 * user wants to create group, need to show him available continents in combobox
	 */	
	public static void populateContinentComboBox() {
		//do only if not populated already
		if (MainWindow.cmbNewGroupContinent.getItemCount() == 0) {
			// get all countries from DB
			continentsList = MainWindow.myDB.getAllContinents();
			
			// add all groups to combo
			for(Continent cntnnt : continentsList) {
				MainWindow.cmbNewGroupContinent.add(cntnnt.getContinentName());
			}
		}
	}

	/**
	 * update Groups Table
	 */
	public static void updateGroupsTable() {		
		// clear table before filling
		MainWindow.tblGroupsBoard.removeAll();
		if (currUser != null){
			//get groups for current user 
			currUserGroups = MainWindow.myDB.getGroupsInUser(currUser.getID());
			//create table items for each group
			TableItem row;
			for(Group g : currUserGroups){
				//create new row
				row = new TableItem(MainWindow.tblGroupsBoard, SWT.NONE);
				//update row text
				row.setText(new String[] { g.getName(), g.getScore().toString()});
			}
		}
		//MainWindow.tblGroupsBoard.pack();
	}
	
	/**
	 * update Grp HighScore Table
	 */
	public static void updateGrpHighScoreTable() {
		// clear table before filling
		MainWindow.tblGrpHighScore.removeAll();
		if (currUser != null && currUser.getCurrGroup() != null) {
			// get users and scores for current group
			List<User> usersInGroup = MainWindow.myDB.getUsersInGroupSorted(currUser.getCurrGroup().getGroupId());
			//create table items for each user
			TableItem row;
			for( User u: usersInGroup){
				row = new TableItem(MainWindow.tblGrpHighScore, SWT.NONE, 0);
				//update row text
				row.setText(new String[] { u.getName(), u.getScore().toString()});
			}
		}
		//MainWindow.tblGrpHighScore.pack();
	}
	
	/**
	 * update Statistics Table
	 */
	public static void updateStatisticsTable() {		
		// clear table before filling
		MainWindow.tblStatistics.removeAll();
		if (currUser != null && !currUser.getName().equals("admin")){
			//update user label
			MainWindow.lblStatisticsUser.setText(currUser.getName());
			//get statistics for current user 
			List<QuestionLog> userQuestions = MainWindow.myDB.getQuestionsByUser(currUser.getID());
			//create table items for each question
			TableItem row;
			for(QuestionLog q : userQuestions){
				//create new row
				row = new TableItem(MainWindow.tblStatistics, SWT.NONE);
				
				String groupName = "ERROR";
				for (Group g : groupList) {
					if (q.getGroup() == g.getId()) {
						groupName = g.getGroupName();
						break;
					}
				}
				
				//update row text
				row.setText(new String[] { q.getTime(), MainWindow.myDB.getCity(q.getCityId()).getCityName(), groupName, Integer.toString(q.getSeconds()), Integer.toString(q.getScore())});
			}
		}
	}
	
}
